#include <stdexcept>

#include "gl_texture.h"

#include "tga_loader.h"

GLenum const eqtest::TextureBinding::tex2enum[] = {
    GL_TEXTURE0,
    GL_TEXTURE1,
    GL_TEXTURE2,
    GL_TEXTURE3,
    GL_TEXTURE4,
    GL_TEXTURE5,
    GL_TEXTURE6,
    GL_TEXTURE7,
};

eqtest::GLTexture::GLTexture(GLEWContext const* context):
GLEWContextHolder(context)
{
    allocateDefault();
}

eqtest::GLTexture::GLTexture(GLenum internalFormat, GLsizei width, GLsizei height, GLEWContext const* context):
GLEWContextHolder(context)
{
    allocateDefault();
    assign(internalFormat, width, height);
}

eqtest::GLTexture::~GLTexture()
{
    if(texture != 0)
        glDeleteTextures(1, &texture);
}

void eqtest::GLTexture::assign(GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* data)
{
    TextureBinding binding(*this);
    
    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data);
    
    glGenerateMipmap(GL_TEXTURE_2D);
}

void eqtest::GLTexture::assign(GLenum internalFormat, GLsizei width, GLsizei height)
{
    GLenum format = GL_LUMINANCE;
    GLenum type = GL_UNSIGNED_BYTE;
    std::unique_ptr<GLubyte> data(new GLubyte [height * ((width + 3) / 4 * 4)] () );
    
    assign(internalFormat, width, height, format, type, data.get());
}

void eqtest::GLTexture::allocateDefault()
{
    texture = 0;
    glGenTextures(1, &texture);
    if(texture == 0)
        throw std::runtime_error("Texture object allocation failed.");
    
    TextureBinding binding(*this);
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
}

eqtest::GLImageTexture::GLImageTexture(const eqtest::TgaImage& image, GLEWContext const* context):
GLTexture(context)
{
    GLenum format;
    if(image.bits_per_pixel() == 24 && image.alpha_bits() == 0)
        format = GL_BGR;
    else if(image.bits_per_pixel() == 32 && image.alpha_bits() == 8)
        format = GL_BGRA;
    else
        throw std::runtime_error("Unsupported pixel format for texture.");
    
    this->assign(GL_RGBA, image.width(), image.height(), format, GL_UNSIGNED_BYTE, image.data());
}
